package com.cn.jx.common.service;

import com.jx.enumType.SQLSepEnum;
import com.jx.exception.MyException;
import com.jx.jpaQuery.ConditionField;
import com.jx.jpaQuery.ConvertCondition;
import com.jx.jpaQuery.QueryCondition;
import com.jx.util.ArrayUtil;
import com.jx.util.Utility;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import static com.jx.enumType.YesNoEnum.NO;
import static com.jx.enumType.YesNoEnum.YES;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Predicate.BooleanOperator;
import javax.persistence.criteria.Root;

/**
 * 
 * @author 姜旭
 * @version v1.11.20.2019
 * @since 
 * <p>创建时间：2019年12月11日
 * <p>功能描述：基本的BaseService服务层 业务层 
 * <p>官方网站：management/admin/index
 * <p>邮箱地址：524577360@qq.com
 */
public abstract class BaseService {
	
	/**定义{@link EntityManager entityManager <tt>实体管理</tt>}*/
	@PersistenceContext
	protected EntityManager entityManager;
	
	/**定义{@link String DEL_FLG <tt>静态常量delFlg</tt>}*/
	private static final String DEL_FLG="delFlg";
	
	/**定义{@link String VALID_FLG <tt>静态常量validFlg</tt>}*/
	private static final String VALID_FLG="validFlg";
	
	private static final String DESC="desc";
	
	private static final Integer _YES=YES.getCode();
	private static final Integer _NO=NO.getCode();
	
	/**
	 * 
	* @Title:getPageables
	* @Description:TODO(<p>初始化{@link Pageable <tt>JPA分页</tt>}信息)
	* <p>邮箱地址: 524577360@qq.com
	* @param pageParam
	* @return
	* Pageable
	* @throws
	 */
	protected Pageable getPageables(QueryCondition pageParam){
		//定义默认排序规则 DESC
		String order=DESC;
		//如果排序字段为空的情况 
		if(Utility.isBlank(pageParam.getSort())){
			//看默认排序字段DefaultSort是否为空。如果有则按照默认字段排序。否则设置默认字段为createTime创建时间
			pageParam.setSort(Utility.isBlank(pageParam.getDefaultSort())?"createTime":pageParam.getDefaultSort());
			//看默认排序规则DefaultOrder是否设置，如果设置则按照设置的，否则按照默认的倒叙排序DESC
			order=Utility.isBlank(pageParam.getDefaultOrder())?DESC:pageParam.getDefaultOrder();
		}else{
			//页面排序字段不为空获取排序规则
			order=pageParam.getOrder();
			if(Utility.isBlank(pageParam.getOrder())){
				//如果排序规则为空则取默认的，如果默认的也为空则默认为倒叙DESC
				order=Utility.isBlank(pageParam.getDefaultOrder())?DESC:pageParam.getDefaultOrder();
			}
		}
		//返回排序规则{@link Sort.Direction DESC} {@link Sort.Direction ASC}
		Sort.Direction sortType=DESC.equals(order)?Sort.Direction.DESC:Sort.Direction.ASC;
		// 把刚才初始化的字段和排序规则设置进sort排序中
		Sort sort = Sort.by(sortType,pageParam.getSort());
		//返回Pageable类
		Pageable pageable =PageRequest.of(pageParam.getPage() - 1, pageParam.getRows(), sort);
		return pageable;
	}
	
	/**
	 * <p>初始化{@link Specification <tt>getSpecification</tt>}
	 * <p>传入参数 {@link QueryCondition <tt>分页参数pageParam</tt>}
	 * @param pageParam
	 * @return {@link <T> 返回值}
	 * 
	 * <pre>
	 * Specification speci=getSpecification({@link QueryCondition pageParam});
	 * </pre>
	 * 
	 */
	protected <T>Specification<T> getSpecification(QueryCondition cond)  throws Exception {
		Specification<T> speci=new Specification<T>(){
			private static final long serialVersionUID = -2020565695438700748L;
			@Override
			public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
				List<Predicate> listAnd =getCondition(root,criteriaBuilder,cond,BooleanOperator.AND);
				List<Predicate> listOr =getCondition(root,criteriaBuilder,cond,BooleanOperator.OR);
				
				Integer del=cond.getStatus()?_NO:_YES;
				Integer valid=cond.getStatus()?_YES:_NO;
				Predicate result=criteriaBuilder.and(criteriaBuilder.equal(root.get(DEL_FLG).as(Integer.class), del));
				result=criteriaBuilder.and(criteriaBuilder.equal(root.get(VALID_FLG).as(Integer.class), valid));
				if(listAnd.size()>0){
					result=criteriaBuilder.and(listAnd.toArray(new Predicate[listAnd.size()]));
				}
				if(listOr.size()>0){
					result=criteriaBuilder.and(criteriaBuilder.or(listOr.toArray(new Predicate[listOr.size()])));
				}
				return result;
			}
		};
		return speci;
	}
	
	
	/**
	 * <p>初始化查询条件
	 * @param Root<?> root
	 * 		  CriteriaBuilder criteriaBuilder
	 *        QueryCondition cond
	 * @return {@link List<Predicate> 返回值}
	 * 
	 */
	protected List<Predicate> getCondition(Root<?> root,CriteriaBuilder criteriaBuilder,QueryCondition cond,BooleanOperator operator){
		List<Predicate> list = new ArrayList<Predicate>();
		Boolean no=cond.getNocondition();
		if(no!=null && no){
			return list;
		}
		//得到其他查询条件
		List<ConditionField> conditField=cond.getConditions();
		if(ArrayUtil.listNotEmpty(conditField)){
			conditField.forEach(field->{
				String name=field.getName();//列
				String value=field.getValue();//值
				SQLSepEnum sep=field.getOperator();//条件
				BooleanOperator oper=field.getOperAndOr();
				if(Utility.isNotBlank(value) && oper.equals(operator)){
					//判断条件的规则 EQ等于 LIKE 模糊查询
					switch (sep) {
					case EQ:
						list.add(criteriaBuilder.equal(root.get(name).as(String.class), value));
						break;
					case LIKE:
						list.add(criteriaBuilder.like(root.get(name).as(String.class), ConvertCondition.getLikeVal(value)));
						break;
					case RLIKE:
						list.add(criteriaBuilder.like(root.get(name).as(String.class), ConvertCondition.getRLikeVal(value)));
						break;
					case LLIKE:
						list.add(criteriaBuilder.like(root.get(name).as(String.class), ConvertCondition.getLLikeVal(value)));
						break;
					default:
						break;
					}
				}
			});
		}
		//返回条件
		return list;
	}
	
	
	/**
	 * 
	* @Title:removeEntityByIds
	* @Description:TODO(批量移除对象 根据ID)
	* <p>邮箱地址: 524577360@qq.com
	* @param ids
	* void
	* @throws
	 */
	@Transactional(propagation=Propagation.REQUIRED)
	public void removeEntityByIds(List<String> ids,Class<?> cla) throws MyException{
		String sql=MessageFormat.format(" delete from {0} where id in(:ids) ", cla.getSimpleName());
		try {
			Query query =entityManager.createQuery(sql);
			query.setParameter("ids",ids);
			query.executeUpdate();
		} catch (Exception e) {
			 throw new MyException(e.getMessage());
		}
	}
	
	/**
	 * 
	* @Title:removeAllEntity
	* @Description:TODO(这里用一句话描述这个方法的作用)
	* <p>邮箱地址: 524577360@qq.com
	* @param cla
	* @throws MyException
	* void
	* @throws
	 */
	@Transactional(propagation=Propagation.REQUIRED)
	public void clearDisabledEntity(Class<?> cla) throws MyException{
		String sql=MessageFormat.format(" delete from {0} where delFlg=:del and validFlg=:valid ", cla.getSimpleName());
		try {
			Query query =entityManager.createQuery(sql);
			query.setParameter("del",_YES);
			query.setParameter("valid",_NO);
			query.executeUpdate();
		} catch (Exception e) {
			 throw new MyException(e.getMessage());
		}
	}
	
	/**
	 * 
	* @Title:recoverEntityById
	* @Description:TODO(批量恢复根据id)
	* <p>邮箱地址: 524577360@qq.com
	* @param ids
	* void
	* @throws
	 */
	@Transactional(propagation=Propagation.REQUIRED)
	public void recoverEntityById(List<String> ids,Class<?> cla) throws MyException{
		String sql=MessageFormat.format(" update {0} c set c.delFlg=:del,c.validFlg=:valid,c.operatTime=:operTime where c.id in(:pids) ", cla.getSimpleName());
		try {
			Query query =entityManager.createQuery(sql);
			query.setParameter("operTime",new Date());
			query.setParameter("pids",ids);
			query.setParameter("del",_NO);
			query.setParameter("valid",_YES);
			query.executeUpdate();
		} catch (Exception e) {
			 throw new MyException(e.getMessage());
		}
	}

	/**
	 * 
	* @Title:deleteEntityByIds
	* @Description:TODO(批量删除 标记删除)
	* <p>邮箱地址: 524577360@qq.com
	* @param ids
	* void
	* @throws
	 */
	@Transactional(propagation=Propagation.REQUIRED)
	public void deleteEntityByIds(List<String> ids,Class<?> cla) throws MyException{
		String sql=MessageFormat.format(" update {0} c set c.delFlg=:del,c.validFlg=:valid ,c.operatTime=:operTime where c.id in(:pids) ", cla.getSimpleName());
		try {
			Query query =entityManager.createQuery(sql);
			query.setParameter("operTime",new Date());
			query.setParameter("pids",ids);
			query.setParameter("del",_YES);
			query.setParameter("valid",_NO);
			query.executeUpdate();
		} catch (Exception e) {
			 throw new MyException(e.getMessage());
		}
	}
	
	/**
	 * 
	* @Title:findEntityByPkid
	* @Description:TODO(根据PKID获取对象)
	* <p>邮箱地址: 524577360@qq.com
	* @param pkid
	* @param cla
	* @return
	* T
	* @throws
	 */
	public <T> T findEntityByPkid(String pkid,Class<T> cla){
		return entityManager.find(cla, pkid);
	}
	
}
